package 遍历器;

import 作用域相关.*;
import 抽象语法树节点.*;
import 抽象语法树节点.后缀表达式.*;
import 抽象语法树节点.字面量类.*;
import 抽象语法树节点.表达式类.*;
import 抽象语法树节点.语句类.*;

public class 引用监听器 extends 抽象语法树基础监听器 {

    public 引用监听器(符号表 符号表) {
        this.符号表 = 符号表;
    }

    private final 符号表 符号表;
    public final 日志 日志 = new 日志();


    @Override
    public void 离开变量定义(变量定义 节点) {
        if (节点.初始值 != null) {
            日志.信息("行 " + 节点.token.getLine() + " 初始值求值类型 " + 节点.初始值.求值类型);
            
            符号表.赋初值(节点, 节点.初始值);
        }
    }

    @Override
    public void 离开数组定义(数组定义 节点) {
        if (节点.初始值 != null) {
            日志.信息("行 " + 节点.token.getLine() + " 初始值求值类型 " + 节点.初始值.求值类型);
        }
    }


    @Override
    public void 离开返回语句(返回语句 节点) {
        var 方法节点 = 符号表.取方法符号(节点.作用域).节点;
        if (节点.返回值 == null) {
            方法节点.求值类型 = 类型索引.空.类型;
        } else {
            方法节点.求值类型 = 节点.求值类型;
        }

        日志.信息("返回语句 求值类型: " + 节点.求值类型);
        
        符号表.返回语句(符号表.取方法符号(节点.作用域), 节点.返回值);
    }


    @Override
    public void 离开负数表达式(负数表达式 节点) {
        节点.求值类型 = 符号表.取负(节点);
        日志.信息("- 求值类型: " + 节点.求值类型);
    }

    @Override
    public void 离开取反表达式(取反表达式 节点) {
        节点.求值类型 = 符号表.取反(节点);
        日志.信息("! 求值类型: " + 节点.求值类型);
    }

    @Override
    public void 离开二元运算表达式(二元运算表达式 节点) {
        节点.求值类型 = 符号表.二元运算(节点.左值, 节点.右值);
        日志.信息(节点.运算符 + " 求值类型: " + 节点.求值类型);
    }

    @Override
    public void 离开关系运算表达式(关系运算表达式 节点) {
        节点.求值类型 = 符号表.关系运算(节点.左值, 节点.右值);
        日志.信息(节点.运算符 + " 求值类型: " + 节点.求值类型);
    }

    @Override
    public void 离开匹值运算表达式(匹值运算表达式 节点) {
        节点.求值类型 = 符号表.匹值运算(节点.左值, 节点.右值);
        日志.信息(节点.运算符 + " 求值类型: " + 节点.求值类型);
    }


    @Override
    public void 离开类型引用(类型引用 节点) {
        var 类型 = 节点.作用域.解析(节点.名称);
        if (类型 instanceof 类型) {
            日志.信息("行 " + 节点.token.getLine() + " 解析类型 " + 节点.名称);
        } else {
            日志.错误("行 " + 节点.token.getLine() + " 找不到类型 " + 节点.名称);
        }
    }

    @Override
    public void 离开标识符(标识符 节点) {
        var 符号 = 节点.作用域.解析(节点.名称);
        日志.信息("行 " + 节点.token.getLine() + " 解析ID " + 节点.名称 + " 为 " + 符号);

        if (符号 != null) {
            日志.信息("行 " + 节点.token.getLine() + " ID " + 节点.名称 + " 求值类型为 " + 符号.类型);
            节点.求值类型 = 符号.类型;
        } else {
            节点.求值类型 = null;
        }
    }

    @Override
    public void 离开整数型字面量(整数型字面量 节点) {
        节点.求值类型 = 类型索引.整数型.类型;
    }

    @Override
    public void 离开浮点型字面量(浮点型字面量 节点) {
        节点.求值类型 = 类型索引.浮点型.类型;
    }

    @Override
    public void 离开字符型字面量(字符型字面量 节点) {
        节点.求值类型 = 类型索引.字符型.类型;
    }

    @Override
    public void 离开逻辑型字面量(逻辑型字面量 节点) {
        节点.求值类型 = 类型索引.逻辑型.类型;
    }


    @Override
    public void 离开函数调用表达式(方法调用表达式 节点) {
        节点.求值类型 = 符号表.方法调用(节点.函数, 节点.参数);
        日志.信息("行 " + 节点.函数.token.getLine() + " 方法调用求值类型: " + 节点.求值类型); // todo : 后续记录一下 start token, 便于获取行号
    }

    @Override
    public void 离开数组访问表达式(数组访问表达式 节点) {
        节点.求值类型 = 符号表.数组访问(节点.数组, 节点.下标);
        日志.信息("行 " + 节点.token.getLine() + " 数组访问求值类型: " + 节点.求值类型);
    }

    @Override
    public void 离开成员访问表达式(成员访问表达式 节点) {
        节点.求值类型 = 符号表.成员访问(节点.对象, 节点.成员名);
        日志.信息("行 " + 节点.token.getLine() + " 成员访问求值类型: " + 节点.求值类型);
    }
    

    @Override
    public void 离开赋值语句(赋值语句 节点) {
        符号表.赋值语句(节点.左值, 节点.右值);
    }


    @Override
    public void 离开判断语句(判断语句 节点) {
        符号表.判断语句(节点);
    }
}
